package com.shiyun.disaster_station.section.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.shiyun.disaster_station.common.LocalCacheUtil;
import com.shiyun.disaster_station.common.ReturnMap;
import com.shiyun.disaster_station.line.bean.po.LineStationRelPo;
import com.shiyun.disaster_station.point.bean.po.LinePointPo;
import com.shiyun.disaster_station.point.service.PointService;
import com.shiyun.disaster_station.section.bean.po.SectionPo;
import com.shiyun.disaster_station.section.bean.req.SectionImportReq;
import com.shiyun.disaster_station.section.dao.SectionMapper;
import com.shiyun.disaster_station.station.service.StationService;
import com.shiyun.disaster_station.utils.ExcelUtils;
import com.shiyun.disaster_station.utils.GeometryUtil;
import org.antlr.runtime.misc.DoubleKeyMap;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineString;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 类 描 述: 区间服务
 * 作   者: 史 云
 * 版   本: 1.0.0
 * 时   间: 2022年01月11日  10:00:00
 */
@Service
public class SectionService {
    @Resource
    LocalCacheUtil localCacheUtil;
    @Resource
    PointService pointService;
    @Resource
    SectionMapper sectionMapper;
    @Resource
    StationService stationService;

    /**
     * 方法描述: 区间导入
     * 作    者: 史 云
     * 时    间: 2022年07月19日  10:31:56
     */
    public ReturnMap importSection(MultipartFile file, List<String> headerTextList, List<String> headerKeyList) {
        try {
            // 获取导入的数据
            List<SectionImportReq> list = ExcelUtils.importExcel(file, headerTextList, headerKeyList, SectionImportReq.class);
            // 对象转换
            AtomicReference<Set<String>> errorMsg = new AtomicReference<>(new HashSet<>(16));
            List<SectionPo> insertList = new ArrayList<>(16);
            AtomicInteger id = new AtomicInteger(1);
            list.forEach(item -> {
                // 先检查线路是否存在
                String lineId = stationService.getExistLineMsg(item.getLineName());
                if (lineId.startsWith(item.getLineName())) {
                    errorMsg.get().add(lineId);
                } else {
                    // 再检查站点是否存在
                    List<String> stationList = Arrays.asList(item.getName().split("～"));
                    if (stationList.size() == 1) {
                        errorMsg.get().add(item.getName() + "区间名称格式不对，不是以～为分隔符");
                    } else {
                        // 第一个站点
                        String preStationName = stationList.get(0).replace("（不含）", "");
                        String preStationId = stationService.getExistStationMsg(preStationName, lineId);
                        if (preStationId.startsWith(preStationName)) {
                            errorMsg.get().add(preStationId);
                        } else {
                            // 第二个站点
                            String nextStationName = stationList.get(1).replace("（不含）", "");
                            String nextStationId = stationService.getExistStationMsg(nextStationName, lineId);
                            if (nextStationId.startsWith(nextStationName)) {
                                errorMsg.get().add(nextStationId);
                            } else {
                                // 计算区间包含的点标识:线路、起始里程、终止里程
                                double mileStart = Double.parseDouble(preStationId.split(StringPool.UNDERSCORE)[1]);
                                double mileEnd = Double.parseDouble(nextStationId.split(StringPool.UNDERSCORE)[1]);
                                // 对象转换
                                SectionPo sectionPo = item.getSectionPo(preStationId, nextStationId, lineId, getLocWgs84(lineId,mileStart,mileEnd));
                                // 设置ID
                                sectionPo.setId(id.getAndAdd(1));
                                insertList.add(sectionPo);
                            }
                        }
                    }
                }
            });
            // 校验
            if (CollectionUtil.isNotEmpty(errorMsg.get())) {
                errorMsg.get().forEach(System.out::println);
                return ReturnMap.error(-1, JSONUtil.toJsonStr(errorMsg.get()));
            }
            // 先清空区间表
            sectionMapper   .delete(null);
            // 插入数据库
            sectionMapper.insertBatchSomeColumn(insertList);
            return ReturnMap.ok(list);
        } catch (IOException e) {
            e.printStackTrace();
            return ReturnMap.error(-1, e.getMessage());
        }
    }

    /**
     * 方法描述: 更新区间的里程信息【特指站点里程信息】
     * 作    者: 史 云
     * 时    间: 2022年07月27日  10:38:04
     */
    public void updateMileage(List<LineStationRelPo> lineStationRelPoList, String lineId){
        // 查询区间信息
        List<SectionPo> sectionList = sectionMapper.selectList(new QueryWrapper<SectionPo>().eq("line_id", lineId));
        // 对象转换
        DoubleKeyMap<Integer,Integer,Double> stationMap = new DoubleKeyMap<>();
        lineStationRelPoList.forEach(item->stationMap.put(item.getLineId(),item.getStationId(),item.getCentralMileage()));
        // 更新里程信息
        sectionList.forEach(item->{
            Double mileStart = stationMap.get(item.getLineId(), item.getStationStartId());
            Double mileEnd = stationMap.get(item.getLineId(), item.getStationEndId());
            item.setMileageStart(Math.min(mileStart,mileEnd));
            item.setMileageEnd(Math.max(mileStart,mileEnd));
            item.setLineCordWgs84(getLocWgs84(lineId,mileStart,mileEnd));
        });
        // 批量更新
        sectionMapper.updateBatch(sectionList);
    }

    /**
     * 方法描述: 获取线段的WKT数据
     * 作    者: 史 云
     * 时    间: 2022年07月27日  10:50:16
     */
    private String getLocWgs84(String lineId,Double mileStart,Double mileEnd){
        List<LinePointPo> pointPoList = pointService.getPointByMileage(Integer.valueOf(lineId),Math.min(mileStart,mileEnd),Math.max(mileStart,mileEnd));
        List<Coordinate> coordinateList = pointPoList.stream().map(point -> new Coordinate(point.getLon(), point.getLat())).collect(Collectors.toList());
        if(CollectionUtil.isNotEmpty(coordinateList) && coordinateList.size()==1){
            coordinateList.remove(0);
        }
        LineString sectionLineString = GeometryUtil.createLineString(coordinateList);
        return sectionLineString.toText();
    }

}
